using System.IO;
using System.IO.Compression;
using System.Security.Cryptography;

namespace SmartBoard.Core.Networking
{
    internal static class CryptUtils
    {
        public static SymmetricAlgorithm CreateSymmetricAlgoritm(EncryptionType encryptionType)
        {
            SymmetricAlgorithm result = null;
            switch (encryptionType)
            {
                case EncryptionType.Rijndael:
                {
                    result = new RijndaelManaged
                                 {
                                     KeySize = 256, 
                                     BlockSize = 256
                                 };
                    break;
                }
            }
            if (result != null)
            {
                result.Mode = CipherMode.CBC;
            }
            return result;
        }

        public static byte[] EncryptDataForAuthenticate(ICryptoTransform ct, byte[] buffer)
        {
            byte[] result = null;
            using (var ms = new MemoryStream())
            {
                using (var cs = new CryptoStream(ms, ct, CryptoStreamMode.Write))
                {
                    cs.Write(buffer, 0, buffer.Length);
                    cs.FlushFinalBlock();
                    result = ms.ToArray();
                }
            }
            return result;
        }

        public static byte[] DecryptDataForAuthenticate(ICryptoTransform ct, byte[] buffer)
        {
            byte[] result = null;
            using (var ms = new MemoryStream(buffer))
            {
                using (var cs = new CryptoStream(ms, ct, CryptoStreamMode.Read))
                {
                    using (var b = new BinaryReader(cs))
                    {
                        ms.Position = 0;
                        result = b.ReadBytes(4096);
                    }
                }
            }
            return result;
        }

        public static byte[] EncryptData(BaseSocketConnection connection, byte[] buffer)
        {
            byte[] result = null;
            if (
                (connection.EventProcessing == EventProcessing.Encrypt)
                || (connection.EventProcessing == EventProcessing.Proxy)
                || (connection.EncryptionType == EncryptionType.SSL && connection.CompressionType == CompressionType.None)
                || (connection.EncryptionType == EncryptionType.None && connection.CompressionType == CompressionType.None)
                )
            {
                result = buffer;
            }
            else
            {
                using(var ms = new MemoryStream())
                {
                    CryptoStream cs = null;
                    GZipStream gs = null;
                    switch (connection.EncryptionType)
                    {
                        case EncryptionType.None:
                        case EncryptionType.SSL:
                            break;
                        default:
                            cs = new CryptoStream(ms, connection.Encryptor, CryptoStreamMode.Write);
                            break;
                    }

                    switch (connection.CompressionType)
                    {
                        case CompressionType.GZIP:
                            if (cs != null)
                            {
                                gs = new GZipStream(cs, CompressionMode.Compress, true);
                            }
                            else
                            {
                                gs = new GZipStream(ms, CompressionMode.Compress, true);
                            }
                            break;
                    }

                    if (gs != null)
                    {
                        gs.Write(buffer, 0, buffer.Length);
                        gs.Flush();
                        gs.Close();
                    }
                    else
                    {
                        cs.Write(buffer, 0, buffer.Length);
                    }

                    if (cs != null)
                    {
                        cs.FlushFinalBlock();
                        cs.Close();
                    }

                    result = ms.ToArray();
                }
            }
            return result;
        }

        public static byte[] DecryptData(BaseSocketConnection connection, byte[] buffer, int maxBufferSize)
        {
            byte[] result = null;
            if (
                (connection.EventProcessing == EventProcessing.Encrypt)
                || (connection.EventProcessing == EventProcessing.Proxy)
                || (connection.EncryptionType == EncryptionType.SSL && connection.CompressionType == CompressionType.None) 
                || (connection.EncryptionType == EncryptionType.None && connection.CompressionType == CompressionType.None)
                  
                )
            {
                result = buffer;
            }
            else
            {
                var ms = new MemoryStream(buffer);
                CryptoStream cs = null;
                GZipStream gs = null;
                switch (connection.EncryptionType)
                {
                    case EncryptionType.None:
                    case EncryptionType.SSL:
                        break;
                    default:
                        cs = new CryptoStream(ms, connection.Decryptor, CryptoStreamMode.Read);
                        break;
                }

                switch (connection.CompressionType)
                {
                    case CompressionType.GZIP:
                    {
                        if (cs != null)
                        {
                            gs = new GZipStream(cs, CompressionMode.Decompress, true);
                        }
                        else
                        {
                            gs = new GZipStream(ms, CompressionMode.Decompress, true);
                        }
                        break;
                    }
                }

                var b = gs != null ? new BinaryReader(gs) : new BinaryReader(cs);
                result = b.ReadBytes(maxBufferSize);
                b.Close();
            }
            return result;
        }
    }
}